package cz.stv.pecinovsky.město;

import cz.stv.pecinovsky.správceplátna.IPosuvný;
import cz.stv.pecinovsky.správceplátna.Kreslítko;
import cz.stv.pecinovsky.správceplátna.Obdélník;
import cz.stv.pecinovsky.správceplátna.SprávcePlátna;
import cz.stv.pecinovsky.správceplátna.Trojúhelník;

import cz.stv.pecinovsky.utility.Barva;
import cz.stv.pecinovsky.utility.Oblast;
import cz.stv.pecinovsky.utility.Pozice;
import cz.stv.pecinovsky.utility.Směr8;


/*******************************************************************************
 * Instance třídy {@code Šipka} představují šipky natočené na východ.
 *
 * @author  Rudolf PECINOVSKÝ
 * @version 1.10.2678 — 2011-10-27
 */
public class Šipka implements IOtočný
     {
//== KONSTANTNÍ ATRIBUTY TŘÍDY =================================================

    private static final int IMPLICITNÍ_X = 0;

    private static final int IMPLICITNÍ_Y = 0;

    private static final int IMPLICITNÍ_MODUL = 50;

    private static final Barva IMPLICITNÍ_BARVA = Barva.ČERNÁ;

    private static final Směr8 IMPLICITNÍ_SMĚR = Směr8.VÝCHOD;

    /** Plátno, na které se bude instance kreslit. */
    private static final SprávcePlátna SP = SprávcePlátna.getInstance();



//== PROMĚNNÉ ATRIBUTY TŘÍDY ===================================================

     /** Počet doposud vytvořených instancí. */
     private static int počet = 0;



//== STATICKÝ INICIALIZAČNÍ BLOK - STATICKÝ KONSTRUKTOR ========================
//== KONSTANTNÍ ATRIBUTY INSTANCÍ ==============================================

    /** Pořadové (identifikační) číslo dané instance. */
    private final int ID;

    /** Obdélníková část představující tělo šipky. */
    private final Obdélník tělo;

    /** Trojúhelníkové zakončení šipky. */
    private final Trojúhelník hlava;

    /** Barva celé šipky, tj. těla i hlavy. */
    private final Barva barva;



//== PROMĚNNÉ ATRIBUTY INSTANCÍ ================================================

    /** Název instance sestávající implicitně z názvu třídy a ID instance */
    private String název;

    /** Bodová x-ová souřadnice instance. */
    private int xPos;

    /** Bodová y-ová souřadnice instance. */
    private int yPos;

    /** Bodová velikost strany čtverce opsaného šipce,
     *  tj. čtverce, do nějž se šipka právě vejde. */
    private int modul;

    /** Směr, do nějž je šipka natočena. */
    private Směr8 směr;



//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ TŘÍDY ========================================
//== OSTATNÍ NESOUKROMÉ METODY TŘÍDY ===========================================

//##############################################################################
//== KONSTRUKTORY A TOVÁRNÍ METODY =============================================

    /***************************************************************************
     * Vytvoří šipku implicitních rozměrů a barvy
     * umístěnou v levém horním rohu plátna.
     */
    public Šipka()
    {
        this(IMPLICITNÍ_X, IMPLICITNÍ_Y);
    }


    /***************************************************************************
     * Vytvoří šipku implicitních rozměrů a barvy
     * umístěnou na zadaných souřadnicích.
     *
     * @param x  Vodorovná souřadnice vytvářené šipky
     * @param y  Svislá souřadnice vytvářené šipky
     */
    public Šipka(int x, int y)
    {
        this(x, y, IMPLICITNÍ_BARVA);
    }


    /***************************************************************************
     * Vytvoří šipku implicitních rozměrů zadané barvy
     * umístěnou na zadaných souřadnicích.
     *
     * @param x  Vodorovná souřadnice vytvářené šipky
     * @param y  Svislá souřadnice vytvářené šipky
     * @param barva  Počáteční barva vytvářené šipky
     */
    public Šipka(int x, int y, Barva barva)
    {
        this(x, y, IMPLICITNÍ_MODUL, barva);
    }


    /***************************************************************************
     * Vytvoří šipku zadaných rozměrů a implicitní barvy
     * umístěnou na zadaných souřadnicích.
     *
     * @param x  Vodorovná souřadnice vytvářené šipky
     * @param y  Svislá souřadnice vytvářené šipky
     * @param modul Bodová velikost strany čtverce opsaného šipce
     */
    public Šipka(int x, int y, int modul)
    {
        this(x, y, modul, IMPLICITNÍ_BARVA);
    }


    /***************************************************************************
     * Vytvoří šipku zadaných rozměrů a zadané barvy
     * umístěnou na zadaných souřadnicích.
     *
     * @param x  Vodorovná souřadnice vytvářené šipky
     * @param y  Svislá souřadnice vytvářené šipky
     * @param modul  Bodová velikost strany čtverce opsaného šipce
     * @param barva  Barva šipky
     */
    public Šipka(int x, int y, int modul, Barva barva)
    {
        this(x, y, modul, barva, IMPLICITNÍ_SMĚR);
    }


    /***************************************************************************
     * Vytvoří šipku zadaných rozměrů a implicitní barvy
     * umístěnou na zadaných souřadnicích a natočenou do zadaného směru.
     *
     * @param x  Vodorovná souřadnice vytvářené šipky
     * @param y  Svislá souřadnice vytvářené šipky
     * @param modul Průměr vytvárené šipky
     * @param směr  Směr, do nějž bude vytvořená šipka natočena
     */
    public Šipka(int x, int y, int modul, Směr8 směr)
    {
        this(x, y, modul, IMPLICITNÍ_BARVA, směr);
    }


    /***************************************************************************
     * Vytvoří šipku zadaných rozměrů a zadané barvy
     * umístěnou na zadaných souřadnicích a natočenou do zadaného směru.
     *
     * @param x  Vodorovná souřadnice vytvářené šipky
     * @param y  Svislá souřadnice vytvářené šipky
     * @param modul Průměr vytvárené šipky
     * @param barva Barva šipky
     * @param směr  Směr, do nějž bude vytvořená šipka natočena
     */
    public Šipka(int x, int y, int modul, Barva barva, Směr8 směr)
    {
        Šipka.počet = Šipka.počet + 1;
        this.ID     = počet;
        
        this.xPos  = x;
        this.yPos  = y;
        this.modul = modul;
        this.barva = barva;
        this.směr  = směr;

        int m2 = modul / 2;
        int m3 = modul / 3;

        Oblast ref = new Oblast(x, y, modul, modul);
        Oblast díl;

        //Tělo - obdélník
        díl = new Oblast(0, m3, m2, m3);
        díl = směr.otočVOblast(díl, ref);
        this.tělo = new Obdélník(díl, barva);

        //Hlava - trojúhelník
        díl = new Oblast(m2, 0, m2, modul);
        díl = směr.otočVOblast(díl, ref);
        this.hlava = new Trojúhelník(díl, barva, směr);
    }



//== ABSTRAKTNÍ METODY =========================================================
//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ INSTANCÍ =====================================

    /***************************************************************************
     * Nastaví novou barvu šipky; nadále si však pamatuje její výchozí barvu.
     *
     * @param nová Zadávaná nová barva
     */
    public void setBarva(Barva nová)
    {
        tělo .setBarva(nová);
        hlava.setBarva(nová);
    }


    // Sada přístupových metod vlastnosti: Pozice ******************************

    /***************************************************************************
     * Vrátí x-ovou (vodorovnou) souřadnici pozice instance.
     *
     * @return  x-ová souřadnice.
     */
    public int getX()
    {
        return xPos;
    }


    /***************************************************************************
     * Vrátí y-ovou (svislou) souřadnici pozice instance.
     *
     * @return  y-ová souřadnice.
     */
    public int getY()
    {
        return yPos;
    }


    /***************************************************************************
     * Vrátí přepravku se svojí aktuální pozicí.
     *
     * @return Aktuální pozice šipky
     */
    @Override
    public Pozice getPozice()
    {
        return new Pozice(getX(), getY());
    }


    /***************************************************************************
     * Nastaví novou pozici šipky.
     *
     * @param p Nastavovaná pozice
     */
    @Override
    public void setPozice(Pozice p)
    {
        this.setPozice(p.x, p.y);
    }


    /***************************************************************************
     * Nastaví novou pozici instance.
     *
     * @param x   Nová x-ová pozice instance
     * @param y   Nová y-ová pozice instance
     */
    @Override
    public void setPozice(int x, int y)
    {
        int dx = x - getX();
        int dy = y - getY();
        SP.nekresli(); {
            tělo .posunVpravo(dx);
            tělo .posunDolů  (dy);
            hlava.posunVpravo(dx);
            hlava.posunDolů  (dy);
        } SP.vraťKresli();
        xPos = x;
        yPos = y;
    }


    // Sada přístupových metod vlastnosti: Rozměr / Modul **********************

    /***************************************************************************
     * Vrátí základní délku, od níž se odvozují všechny rozměry objektu -
     * pro šipku je to její délka, které je současně šířkou základny hlavy.
     *
     * @return Délka a šířka šipky
     */
    @Override
    public int getModul()
    {
        return modul;
    }


    /***************************************************************************
     * Nastaví nový modul = "čtvercový" rozměr instance;
     * na zadaný rozměr se nastaví její výška i šířka.
     *
     * @param modul  Nově nastavovaný rozměr v obou směrech; rozměr>0
     */
    @Override
    public void setModul(int modul)
    {
        if (modul <= 0) {
            throw new IllegalArgumentException(
                    "\nVelikost modulu musí být nezáporná - zadáno " + modul);
        }
        int x  = getX();
        int y  = getY();
        int m  = modul;
        int m2 = m / 2;
        int m3 = m / 3;

        Oblast ref = new Oblast(x, y, m, m);
        Oblast díl;

        SP.nekresli(); {
            //Tělo - obdélník
            díl = new Oblast(0, m3, m2, m3);
            díl = směr.otočVOblast(díl, ref);
            this.tělo.setOblast(díl);
    
            //Hlava - trojúhelník
            díl = new Oblast(m2, 0, m2, modul);
            díl = směr.otočVOblast(díl, ref);
            this.hlava.setOblast(díl);
        } SP.vraťKresli();
        this.modul = modul;
    }


    /***************************************************************************
     * Vrátí směr, do nějž je šipka natočena.
     *
     * @return Směr, do nějž je šipka natočena
     */
    @Override
    public Směr8 getSměr()
    {
//        return hlava.getSměr();
        return směr;
    }


    /***************************************************************************
     * Natočí šipku do zadaného směru.
     *
     * @param směr  Směr, do nějž se má šipka natočit
     */
    @Override
    public void setSměr(Směr8 směr)
    {
        if (! směr.isHlavní()) {
            throw new IllegalArgumentException(
                "\nNebyl zadán hlavní směr - zadáno " + směr);
        }
        this.směr = směr;
        this.hlava.setSměr(směr);
        this.setModul(modul);
    }



//== OSTATNÍ NESOUKROMÉ METODY INSTANCÍ ========================================

    /***************************************************************************
     * Vrací textovou reprezentaci (podpis) dané instance
     * používanou především k ladicím účelům.
     *
     * @return Požadovaná textová reprezentace
     */
    @Override
    public String toString()
    {
        return "Šipka_" + ID + "(" + getPozice() + ", modul=" + getModul() +
               ", barva=" + barva + ")";
    }


    /***************************************************************************
     * Prostřednictvím dodaného kreslítka vykreslí obraz své instance.
     *
     * @param kreslítko Kreslítko, které nakreslí instanci
     */
    @Override
    public void nakresli(Kreslítko kreslítko)
    {
        tělo .nakresli(kreslítko);
        hlava.nakresli(kreslítko);
    }


    /***************************************************************************
     * Zprůsvitní šipku, tj. nastaví jí průsvitnější barvu.
     */
    public void průsvitná()
    {
        tělo .setBarva(barva.průsvitná());
        hlava.setBarva(barva.průsvitná());
    }


    /***************************************************************************
     * Vrátí šipce její výchozí barvu.
     */
    public void vraťBarva()
    {
        setBarva(barva);
    }



//== SOUKROMÉ A POMOCNÉ METODY TŘÍDY ===========================================
//== SOUKROMÉ A POMOCNÉ METODY INSTANCÍ ========================================
//== INTERNÍ DATOVÉ TYPY =======================================================
//== TESTY A METODA MAIN =======================================================
//
//    /***************************************************************************
//     * Testovací metoda.
//     */
//    public static void test()
//    {
//        Šipka inst = new Šipka();
//    }
//    /** @param args Parametry příkazového řádku - nepoužívané. */
//    public static void main( String[] args )  {  test();  }
}

